package services

import (
	"database/sql"
	"errors"
	"fmt"
	"time"

	"miracle-recorder/internal/models"
	"github.com/go-redis/redis/v8"
	"golang.org/x/crypto/bcrypt"
)

type UserService struct {
	db    *sql.DB
	redis *redis.Client
}

func NewUserService(db *sql.DB, redis *redis.Client) *UserService {
	return &UserService{db: db, redis: redis}
}

func (s *UserService) CreateUser(user *models.User) error {
	// 哈希密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
	if err != nil {
		return fmt.Errorf("failed to hash password: %w", err)
	}

	query := `
		INSERT INTO users (username, email, password, avatar, bio, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
		RETURNING id
	`

	err = s.db.QueryRow(query,
		user.Username,
		user.Email,
		string(hashedPassword),
		user.Avatar,
		user.Bio,
		time.Now(),
		time.Now(),
	).Scan(&user.ID)

	if err != nil {
		return fmt.Errorf("failed to create user: %w", err)
	}

	return nil
}

func (s *UserService) GetUserByEmail(email string) (*models.User, error) {
	query := `
		SELECT id, username, email, password, avatar, bio, created_at, updated_at
		FROM users
		WHERE email = $1
	`

	user := &models.User{}
	err := s.db.QueryRow(query, email).Scan(
		&user.ID,
		&user.Username,
		&user.Email,
		&user.Password,
		&user.Avatar,
		&user.Bio,
		&user.CreatedAt,
		&user.UpdatedAt,
	)

	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, fmt.Errorf("user not found")
		}
		return nil, fmt.Errorf("failed to get user: %w", err)
	}

	return user, nil
}

func (s *UserService) GetUserByID(id int) (*models.User, error) {
	query := `
		SELECT id, username, email, password, avatar, bio, created_at, updated_at
		FROM users
		WHERE id = $1
	`

	user := &models.User{}
	err := s.db.QueryRow(query, id).Scan(
		&user.ID,
		&user.Username,
		&user.Email,
		&user.Password,
		&user.Avatar,
		&user.Bio,
		&user.CreatedAt,
		&user.UpdatedAt,
	)

	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, fmt.Errorf("user not found")
		}
		return nil, fmt.Errorf("failed to get user: %w", err)
	}

	return user, nil
}

func (s *UserService) UpdateUser(user *models.User) error {
	query := `
		UPDATE users
		SET username = $1, email = $2, avatar = $3, bio = $4, updated_at = $5
		WHERE id = $6
	`

	_, err := s.db.Exec(query,
		user.Username,
		user.Email,
		user.Avatar,
		user.Bio,
		time.Now(),
		user.ID,
	)

	if err != nil {
		return fmt.Errorf("failed to update user: %w", err)
	}

	return nil
}

func (s *UserService) ValidatePassword(password, hashedPassword string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
	return err == nil
}

type TopicService struct {
	db    *sql.DB
	redis *redis.Client
}

func NewTopicService(db *sql.DB, redis *redis.Client) *TopicService {
	return &TopicService{db: db, redis: redis}
}

func (s *TopicService) CreateTopic(topic *models.Topic) error {
	query := `
		INSERT INTO topics (title, description, creator_id, category, tags, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
		RETURNING id
	`

	err := s.db.QueryRow(query,
		topic.Title,
		topic.Description,
		topic.CreatorID,
		topic.Category,
		topic.Tags,
		time.Now(),
		time.Now(),
	).Scan(&topic.ID)

	if err != nil {
		return fmt.Errorf("failed to create topic: %w", err)
	}

	return nil
}

func (s *TopicService) GetTopic(id int) (*models.Topic, error) {
	query := `
		SELECT t.id, t.title, t.description, t.creator_id, t.category, t.tags, 
		       t.ai_summary, t.credibility_score, t.view_count, t.like_count, 
		       t.comment_count, t.share_count, t.status, t.created_at, t.updated_at,
		       u.id, u.username, u.email, u.avatar, u.bio, u.created_at, u.updated_at
		FROM topics t
		LEFT JOIN users u ON t.creator_id = u.id
		WHERE t.id = $1
	`

	topic := &models.Topic{}
	var creatorUser models.User

	err := s.db.QueryRow(query, id).Scan(
		&topic.ID,
		&topic.Title,
		&topic.Description,
		&topic.CreatorID,
		&topic.Category,
		&topic.Tags,
		&topic.AISummary,
		&topic.CredibilityScore,
		&topic.ViewCount,
		&topic.LikeCount,
		&topic.CommentCount,
		&topic.ShareCount,
		&topic.Status,
		&topic.CreatedAt,
		&topic.UpdatedAt,
		&creatorUser.ID,
		&creatorUser.Username,
		&creatorUser.Email,
		&creatorUser.Avatar,
		&creatorUser.Bio,
		&creatorUser.CreatedAt,
		&creatorUser.UpdatedAt,
	)

	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, fmt.Errorf("topic not found")
		}
		return nil, fmt.Errorf("failed to get topic: %w", err)
	}

	topic.Creator = creatorUser
	return topic, nil
}

func (s *TopicService) ListTopics(limit, offset int, category string) ([]*models.Topic, error) {
	query := `
		SELECT t.id, t.title, t.description, t.creator_id, t.category, t.tags, 
		       t.ai_summary, t.credibility_score, t.view_count, t.like_count, 
		       t.comment_count, t.share_count, t.status, t.created_at, t.updated_at,
		       u.id, u.username, u.email, u.avatar, u.bio, u.created_at, u.updated_at
		FROM topics t
		LEFT JOIN users u ON t.creator_id = u.id
		WHERE t.status = 'active'
	`

	args := []interface{}{}
	if category != "" {
		query += " AND t.category = $1"
		args = append(args, category)
	}

	query += " ORDER BY t.created_at DESC LIMIT $" + fmt.Sprintf("%d", len(args)+1) + " OFFSET $" + fmt.Sprintf("%d", len(args)+2)
	args = append(args, limit, offset)

	rows, err := s.db.Query(query, args...)
	if err != nil {
		return nil, fmt.Errorf("failed to list topics: %w", err)
	}
	defer rows.Close()

	var topics []*models.Topic
	for rows.Next() {
		topic := &models.Topic{}
		var creatorUser models.User

		err := rows.Scan(
			&topic.ID,
			&topic.Title,
			&topic.Description,
			&topic.CreatorID,
			&topic.Category,
			&topic.Tags,
			&topic.AISummary,
			&topic.CredibilityScore,
			&topic.ViewCount,
			&topic.LikeCount,
			&topic.CommentCount,
			&topic.ShareCount,
			&topic.Status,
			&topic.CreatedAt,
			&topic.UpdatedAt,
			&creatorUser.ID,
			&creatorUser.Username,
			&creatorUser.Email,
			&creatorUser.Avatar,
			&creatorUser.Bio,
			&creatorUser.CreatedAt,
			&creatorUser.UpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan topic: %w", err)
		}

		topic.Creator = creatorUser
		topics = append(topics, topic)
	}

	return topics, nil
}

func (s *TopicService) UpdateTopic(topic *models.Topic) error {
	query := `
		UPDATE topics
		SET title = $1, description = $2, category = $3, tags = $4, 
		    ai_summary = $5, credibility_score = $6, updated_at = $7
		WHERE id = $8
	`

	_, err := s.db.Exec(query,
		topic.Title,
		topic.Description,
		topic.Category,
		topic.Tags,
		topic.AISummary,
		topic.CredibilityScore,
		time.Now(),
		topic.ID,
	)

	if err != nil {
		return fmt.Errorf("failed to update topic: %w", err)
	}

	return nil
}

func (s *TopicService) DeleteTopic(id int) error {
	query := `
		UPDATE topics
		SET status = 'deleted', updated_at = $1
		WHERE id = $2
	`

	_, err := s.db.Exec(query, time.Now(), id)
	if err != nil {
		return fmt.Errorf("failed to delete topic: %w", err)
	}

	return nil
}